#include "intN.h"
#define DEBUG(STR) do{for(auto e : STR){cout << (int) e << ',';}cout << endl;}while(0)
bool& intN::operator[](int index){
	return _body[index];
}
int intN::_div2(string& str){
	int t = 0;
	for(int i = 0; i < (int) str.length(); i++){
		t = t * 10 + str[i];
		str[i] = t / 2;
		t &= 1;
	}
	return t;
}
intN::intN(){
	;
}
intN::intN(unsigned long long num){
	int i = intN_width - 1;
	for(; num; num >>= 1, i--){
		(*this)[i] = (num & 1) ? true : false;
	}
	for(; i >= 0; i--){
		(*this)[i] = false;
	}
}
void intN::read(string str){
	for(int i = 0; i < (int) str.length(); i++){
		str[i] -= '0';
	}
	for(int i = intN_width - 1; i >= 0; i--){
		(*this)[i] = _div2(str);
	}
	for(int i = 0; i < (int) str.length(); i++){
		str[i] += '0';
	}
}
string intN::toBits(){
	string res(intN_width, '0');
	for(int i = 0; i < intN_width; i++){
		res[i] = ((*this)[i]) ? '1' : '0';
	}
	return res;
}
string intN::toDigits(){
	string res(intN_width, 0);
	int i = 0;
	for(; (*this)[i] == 0; i++);
	for(; i < intN_width; i++){
		for(int j = 0; j < intN_width; j++){
			res[j] *= 2;
		}
		res[intN_width - 1] += (*this)[i] ? 1 : 0;
		if(i % 3 == 0)
			for(int j = intN_width - 1; j >= 1; j--){
				res[j - 1] += res[j] / 10;
				res[j] %= 10;
			}
	}
	/*
	while(1){
		if(i >= intN_width)break;
		for(int j = 0; j < intN_width; j++){
			res[j] *= 2;
		}
		res[intN_width - 1] += (*this)[i] ? 1 : 0;
		if(i % 3 == 0)
			for(int j = intN_width - 1; j >= 1; j--){
				res[j - 1] += res[j] / 10;
				res[j] %= 10;
			}
		i++;
		if(i >= intN_width)break;
		for(int j = 0; j < intN_width; j++){
			res[j] *= 2;
		}
		res[intN_width - 1] += (*this)[i] ? 1 : 0;
		i++;
		if(i >= intN_width)break;
		for(int j = 0; j < intN_width; j++){
			res[j] *= 2;
		}
		res[intN_width - 1] += (*this)[i] ? 1 : 0;
		i++;
	}
	*/
	/*
	for(int j = intN_width - 1; j >= 1; j--){
		res[j - 1] += res[j] / 10;
		res[j] %= 10;
	}
	*/
	for(int i = 0; i < intN_width; i++){
		res[i] += '0';
	}
	int n_of_0 = 0;
	for(int i = 0; i < intN_width; i++){
		if(res[i] == '0'){
			n_of_0++;
		}
	}
	return string(res.begin() + n_of_0, res.end());
}
intN intN::operator=(unsigned long long num){
	int i = intN_width - 1;
	for(; num; num >>= 1, i--){
		(*this)[i] = (num & 1) ? true : false;
	}
	for(; i >= 0; i--){
		(*this)[i] = false;
	}
	return *this;
}
intN intN::operator&(const intN& b){
	intN res;
	for(int i = 0; i < intN_width; i++){
		res[i] = this->_body[i] & b._body[i];
	}
	return res;
}
intN intN::operator|(const intN& b){
	intN res;
	for(int i = 0; i < intN_width; i++){
		res[i] = this->_body[i] | b._body[i];
	}
	return res;
}
intN intN::operator^(const intN& b){
	intN res;
	for(int i = 0; i < intN_width; i++){
		res[i] = this->_body[i] ^ b._body[i];
	}
	return res;
}
intN intN::operator~(){
	intN res;
	for(int i = 0; i < intN_width; i++){
		res[i] = !(this->_body[i]);
	}
	return res;
}
intN intN::operator<<(int n){
	intN res;
	int i = 0;
	for(; i + n < intN_width; i++){
		res[i] = this->_body[i + n];
	}
	for(; i < n; i++){
		res[i] = false;
	}
	return res;
}
intN intN::operator>>(int n){
	intN res;
	int i = intN_width - 1;
	for(; i >= n; i--){
		res[i] = this->_body[i - n];
	}
	for(; i >= 0; i--){
		res[i] = false;
	}
	return res;
}
bool intN::operator>(const intN& b){
	for(int i = 0; i < intN_width; i++){
		if(this->_body[i] == true && b._body[i] == false){
			return true;
		}
		if(this->_body[i] == false && b._body[i] == true){
			return false;
		}
	}
	return false;
}
bool intN::operator<(const intN& b){
	for(int i = 0; i < intN_width; i++){
		if(this->_body[i] == true && b._body[i] == false){
			return false;
		}
		if(this->_body[i] == false && b._body[i] == true){
			return true;
		}
	}
	return false;
}
bool intN::operator!=(const intN& b){
	return (*this < b) || (*this > b);
}
bool intN::operator==(const intN& b){
	return !(*this != b);
}
bool intN::operator>=(const intN& b){
	return (*this > b) || (*this == b);
}
bool intN::operator<=(const intN& b){
	return (*this < b) || (*this == b);
}
intN intN::operator+(const intN& b){
	intN and_v, xor_v, temp;
	and_v = *this & b;
	xor_v = *this ^ b;
	while(and_v > intN(0ULL)){
		and_v = and_v << 1;
		temp = xor_v;
		xor_v = xor_v ^ and_v;
		and_v = temp & and_v;
	}
	return xor_v;
}
